package incubator.kristian;

import group.GeoGroup;
import gui.CameraControlPanel;
import gui.ControlPanel;
import gui.InputAdapter;
import gui.MouseControlPanel;
import gui.OptionPanel;
import gui.SaveLoadPanel;
import gui.StatusBar;

import java.applet.*;
import java.awt.BorderLayout;
import java.awt.GraphicsConfiguration;

import javax.media.j3d.*;
import javax.vecmath.*;

import toolbox.Toolbox;

import node.IntersectionValidator;
import node.appearance.AppearanceFactory;
import node.appearance.MetalAppearanceFactory;

import com.sun.j3d.utils.applet.JMainFrame;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.universe.SimpleUniverse;

import component.Ball;
import component.ComponentFactory;
import component.Structure;

import controller.AbstractController;
import controller.CameraController;
import controller.GridController;
import controller.PlaceFreeController;
import controller.PlaceNewController;
import controller.SelectionController;
import controller.TransformController;
import controller.camera.Camera;

public class TestMain extends Applet {

	private static final long serialVersionUID = 8808664324953907581L;

	public static void main(String[] args) {
		JMainFrame frame = new JMainFrame(new TestMain(), 640, 480);
		frame.setTitle("GeoStructure 3D");
	}
	
	private Canvas3D cv;
	private Camera camera;
	private Locale locale;
	private BranchGroup root;
	private BranchGroup pickableBranch;
	private GeoGroup nonpickableBranch;
	private BranchGroup grid;
	private Structure structure;
	private ComponentFactory componentFactory;

	@Override
	public void init() {
		setupCanvas();
		setupUniverse();
		setupAppearanceFactory();
		setupStructure();
		setupLights();
		setupComponentFactory();
		createRootComponent();
		setupGUI();
		compileAndAddRootToScene();
	}



	private void setupCanvas() {
		GraphicsConfiguration gc = SimpleUniverse.getPreferredConfiguration();
		cv = new Canvas3D(gc);
		cv.setFocusable(true);
		setLayout(new BorderLayout());
		add(cv , BorderLayout.CENTER);
	}

	private void setupUniverse() {
		VirtualUniverse universe = new VirtualUniverse();
		locale = new Locale(universe);
		camera = new Camera();
		BranchGroup viewBranch = camera.createView(cv);
		locale.addBranchGraph(viewBranch);
	}

	private void setupAppearanceFactory() {
		AppearanceFactory af = new MetalAppearanceFactory();
		Toolbox.setAppearanceFactory(af);
	}
	
	private void setupStructure() {
		GeoGroup permanentGroup = new GeoGroup();
		GeoGroup tempGroup = new GeoGroup();
		this.nonpickableBranch = new GeoGroup();
		structure = new Structure(permanentGroup, tempGroup, nonpickableBranch);
		pickableBranch = new BranchGroup();
		pickableBranch.addChild(permanentGroup);
		pickableBranch.addChild(tempGroup);
		root = new BranchGroup();
		root.addChild(pickableBranch);
		root.addChild(nonpickableBranch);
		
		grid = new BranchGroup();
		grid.setCapability(BranchGroup.ALLOW_DETACH);
		grid.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
		grid.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
		root.addChild(grid);

	}
	
	private void setupLights() {
		Bounds bounds = new BoundingSphere(new Point3d(0,0,0), 100);
		DirectionalLight dl = new DirectionalLight(new Color3f(1f , 1f , 1f) , new Vector3f(-1 , -1 , -1));
		dl.setInfluencingBounds(bounds);
		root.addChild(dl);

		AmbientLight amLight = new AmbientLight();
		amLight.setInfluencingBounds(bounds);
		root.addChild(amLight);
		
		PointLight p1 = new PointLight(new Color3f(0.3f, 0.3f, 0.3f), new Point3f(-10f, -10f, 10f), new Point3f(0.4f, 0f, 0f));
		p1.setInfluencingBounds(bounds);
		root.addChild(p1);
	}
	
	private void setupComponentFactory() {
		IntersectionValidator validator = new IntersectionValidator(structure.getPermanentGeoGroup());
		componentFactory = new ComponentFactory(validator);
	}
	
	private void createRootComponent() {
		Ball ball = componentFactory.createBall(new Point3d(0, 0, 0));
		ball.setRoot(true);
		structure.addPermanentComponent(ball);
	}
	
	private void setupGUI() {
		StatusBar statusBar = new StatusBar();
		OptionPanel optionPanel = new OptionPanel();
		InputAdapter adapter = new InputAdapter(this.cv);
		
		CameraController camControl = new CameraController(cv, pickableBranch, camera);		
		AbstractController placeNewController = new PlaceNewController(cv , pickableBranch, structure, componentFactory);
		AbstractController placeFreeController = new PlaceFreeController(cv, pickableBranch, structure, componentFactory, camera);
		AbstractController selectionController = new SelectionController(cv, pickableBranch, structure, optionPanel, componentFactory);
		AbstractController transformController = new TransformController(cv, pickableBranch, structure, optionPanel, statusBar, camControl);
		adapter.addInputListener(camControl);
		MouseControlPanel mouseControl = new MouseControlPanel(adapter, placeNewController , placeFreeController , selectionController, transformController);
		SaveLoadPanel saveLoad = new SaveLoadPanel(structure, componentFactory);
		ControlPanel controlPanel = new ControlPanel(mouseControl, new CameraControlPanel(camControl), saveLoad);
		add(controlPanel, BorderLayout.NORTH);
		add(statusBar, BorderLayout.SOUTH);
		controlPanel.add(optionPanel, BorderLayout.SOUTH);
		
		new GridController(grid, camControl, optionPanel);
	}
	
	private void compileAndAddRootToScene() {
		root.compile();
		locale.addBranchGraph(root);		
	}

}
